package com.example.bicycle.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
@Slf4j
public class RedisCache
{
    @Autowired(required = false)
    public RedisTemplate redisTemplate;

    /**
     * 检查Redis是否可用
     */
    private boolean isRedisAvailable() {
        if (redisTemplate == null) {
            return false;
        }
        try {
            redisTemplate.getConnectionFactory().getConnection().ping();
            return true;
        } catch (Exception e) {
            log.debug("Redis连接检查失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 缓存基本的对象，Integer、String、实体类等
     *
     * @param key 缓存的键值
     * @param value 缓存的值
     */
    public <T> void setCacheObject(final String key, final T value)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，跳过缓存操作: setCacheObject({})", key);
            return;
        }
        try {
            redisTemplate.opsForValue().set(key, value);
        } catch (Exception e) {
            log.error("Redis缓存存储失败: {}, key: {}", e.getMessage(), key);
        }
    }

    /**
     * 缓存基本的对象，Integer、String、实体类等
     *
     * @param key 缓存的键值
     * @param value 缓存的值
     * @param timeout 时间
     * @param timeUnit 时间颗粒度
     */
    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，跳过缓存操作: setCacheObject({}, timeout: {})", key, timeout);
            return;
        }
        try {
            redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
        } catch (Exception e) {
            log.error("Redis缓存存储失败: {}, key: {}", e.getMessage(), key);
        }
    }

    /**
     * 设置有效时间
     *
     * @param key Redis键
     * @param timeout 超时时间
     * @return true=设置成功；false=设置失败
     */
    public boolean expire(final String key, final long timeout)
    {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置有效时间
     *
     * @param key Redis键
     * @param timeout 超时时间
     * @param unit 时间单位
     * @return true=设置成功；false=设置失败
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，跳过过期时间设置: expire({})", key);
            return false;
        }
        try {
            return redisTemplate.expire(key, timeout, unit);
        } catch (Exception e) {
            log.error("Redis设置过期时间失败: {}, key: {}", e.getMessage(), key);
            return false;
        }
    }

    /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(final String key)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，返回null: getCacheObject({})", key);
            return null;
        }
        try {
            ValueOperations<String, T> operation = redisTemplate.opsForValue();
            return operation.get(key);
        } catch (Exception e) {
            log.error("Redis缓存读取失败: {}, key: {}", e.getMessage(), key);
            return null;
        }
    }

    /**
     * 删除单个对象
     *
     * @param key
     */
    public boolean deleteObject(final String key)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，跳过删除操作: deleteObject({})", key);
            return false;
        }
        try {
            return redisTemplate.delete(key);
        } catch (Exception e) {
            log.error("Redis删除失败: {}, key: {}", e.getMessage(), key);
            return false;
        }
    }

    /**
     * 删除集合对象
     *
     * @param collection 多个对象
     * @return
     */
    public long deleteObject(final Collection collection)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，跳过批量删除操作");
            return 0;
        }
        try {
            return redisTemplate.delete(collection);
        } catch (Exception e) {
            log.error("Redis批量删除失败: {}", e.getMessage());
            return 0;
        }
    }

    /**
     * 缓存List数据
     *
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @return 缓存的对象
     */
    public <T> long setCacheList(final String key, final List<T> dataList)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，跳过List缓存: setCacheList({})", key);
            return 0;
        }
        try {
            Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
            return count == null ? 0 : count;
        } catch (Exception e) {
            log.error("Redis List缓存失败: {}, key: {}", e.getMessage(), key);
            return 0;
        }
    }

    /**
     * 获得缓存的list对象
     *
     * @param key 缓存的键值
     * @return 缓存键值对应的数据
     */
    public <T> List<T> getCacheList(final String key)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，返回空List: getCacheList({})", key);
            return new ArrayList<>();
        }
        try {
            List<T> result = redisTemplate.opsForList().range(key, 0, -1);
            return result == null ? new ArrayList<>() : result;
        } catch (Exception e) {
            log.error("Redis List读取失败: {}, key: {}", e.getMessage(), key);
            return new ArrayList<>();
        }
    }

    /**
     * 缓存Set
     *
     * @param key 缓存键值
     * @param dataSet 缓存的数据
     * @return 缓存数据的对象
     */
    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，跳过Set缓存: setCacheSet({})", key);
            return null;
        }
        try {
            BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
            Iterator<T> it = dataSet.iterator();
            while (it.hasNext())
            {
                setOperation.add(it.next());
            }
            return setOperation;
        } catch (Exception e) {
            log.error("Redis Set缓存失败: {}, key: {}", e.getMessage(), key);
            return null;
        }
    }

    /**
     * 获得缓存的set
     *
     * @param key
     * @return
     */
    public <T> Set<T> getCacheSet(final String key)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，返回空Set: getCacheSet({})", key);
            return new HashSet<>();
        }
        try {
            Set<T> result = redisTemplate.opsForSet().members(key);
            return result == null ? new HashSet<>() : result;
        } catch (Exception e) {
            log.error("Redis Set读取失败: {}, key: {}", e.getMessage(), key);
            return new HashSet<>();
        }
    }

    /**
     * 缓存Map
     *
     * @param key
     * @param dataMap
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，跳过Map缓存: setCacheMap({})", key);
            return;
        }
        try {
            if (dataMap != null) {
                redisTemplate.opsForHash().putAll(key, dataMap);
            }
        } catch (Exception e) {
            log.error("Redis Map缓存失败: {}, key: {}", e.getMessage(), key);
        }
    }

    /**
     * 获得缓存的Map
     *
     * @param key
     * @return
     */
    public <T> Map<String, T> getCacheMap(final String key)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，返回空Map: getCacheMap({})", key);
            return new HashMap<>();
        }
        try {
            Map<String, T> result = redisTemplate.opsForHash().entries(key);
            return result == null ? new HashMap<>() : result;
        } catch (Exception e) {
            log.error("Redis Map读取失败: {}, key: {}", e.getMessage(), key);
            return new HashMap<>();
        }
    }

    /**
     * 往Hash中存入数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @param value 值
     */
    public <T> void setCacheMapValue(final String key, final String hKey, final T value)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，跳过Hash缓存: setCacheMapValue({}, {})", key, hKey);
            return;
        }
        try {
            redisTemplate.opsForHash().put(key, hKey, value);
        } catch (Exception e) {
            log.error("Redis Hash缓存失败: {}, key: {}, hKey: {}", e.getMessage(), key, hKey);
        }
    }

    /**
     * 获取Hash中的数据
     *
     * @param key Redis键
     * @param hKey Hash键
     * @return Hash中的对象
     */
    public <T> T getCacheMapValue(final String key, final String hKey)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，返回null: getCacheMapValue({}, {})", key, hKey);
            return null;
        }
        try {
            HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
            return opsForHash.get(key, hKey);
        } catch (Exception e) {
            log.error("Redis Hash读取失败: {}, key: {}, hKey: {}", e.getMessage(), key, hKey);
            return null;
        }
    }

    /**
     * 删除Hash中的数据
     * 
     * @param key
     * @param hkey
     */
    public void delCacheMapValue(final String key, final String hkey)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，跳过Hash删除: delCacheMapValue({}, {})", key, hkey);
            return;
        }
        try {
            HashOperations hashOperations = redisTemplate.opsForHash();
            hashOperations.delete(key, hkey);
        } catch (Exception e) {
            log.error("Redis Hash删除失败: {}, key: {}, hKey: {}", e.getMessage(), key, hkey);
        }
    }

    /**
     * 获取多个Hash中的数据
     *
     * @param key Redis键
     * @param hKeys Hash键集合
     * @return Hash对象集合
     */
    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，返回空List: getMultiCacheMapValue({})", key);
            return new ArrayList<>();
        }
        try {
            List<T> result = redisTemplate.opsForHash().multiGet(key, hKeys);
            return result == null ? new ArrayList<>() : result;
        } catch (Exception e) {
            log.error("Redis批量Hash读取失败: {}, key: {}", e.getMessage(), key);
            return new ArrayList<>();
        }
    }

    /**
     * 获得缓存的基本对象列表
     *
     * @param pattern 字符串前缀
     * @return 对象列表
     */
    public Collection<String> keys(final String pattern)
    {
        if (!isRedisAvailable()) {
            log.warn("Redis不可用，返回空集合: keys({})", pattern);
            return new ArrayList<>();
        }
        try {
            Collection<String> result = redisTemplate.keys(pattern);
            return result == null ? new ArrayList<>() : result;
        } catch (Exception e) {
            log.error("Redis keys查询失败: {}, pattern: {}", e.getMessage(), pattern);
            return new ArrayList<>();
        }
    }

    /**
     * 获取Redis连接状态
     */
    public boolean isConnected() {
        return isRedisAvailable();
    }
}
